iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0
Modern Web

用 LINE OA 打造中小企業訂單系統:從零開始的 30 天實作紀錄系列 第 16

讓表單跑起來:靜態檔部署 + ngrok + Rich Menu 綁定

  • 分享至 

  • xImage
  •  

昨天我們設計了 LIFF 訂單表單(前端 UX + 驗證),但要真正跑起來還需要部署方式與 LINE 綁定。

今天將帶你用「純靜態檔 + ngrok」快速讓表單在手機 LINE 中開啟,並示範如何把 LIFF 網址綁到 Rich Menu,讓顧客一鍵就能打開下單表單。


為什麼要做落地測試?

  • 本地 localhost 無法被手機 LINE 打開。

  • LIFF Endpoint URL 必須是公開 HTTPS 網址

  • 使用 ngrok 可快速將本機專案公開測試。


準備靜態檔

liff-form/
├─ index.html
└─ app.js

index.html

<!doctype html>
<html lang="zh-Hant">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>LIFF 訂單表單</title>
  <script src="https://static.line-scdn.net/liff/edge/2/sdk.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
  <h1>下單表單</h1>
  <form id="orderForm">
    <input type="hidden" id="userId" />
    <label>商品<select id="product"><option value="">請選擇</option><option value="紅茶拿鐵">紅茶拿鐵</option><option value="起司蛋餅">起司蛋餅</option></select></label>
    <label>數量<input type="number" id="quantity" min="1" /></label>
    <label>電話<input type="tel" id="phone" placeholder="09xxxxxxxx" /></label>
    <label>取貨方式<select id="pickup"><option value="">請選擇</option><option value="自取">自取</option><option value="外送">外送</option></select></label>
    <button id="submitBtn" type="submit" disabled>送出</button>
  </form>
  <script src="./app.js"></script>
</body>
</html>

app.js

const LIFF_ID = "YOUR_LIFF_ID";
const API_BASE = "https://你的後端或ngrok域名";

async function init() {
  await liff.init({ liffId: LIFF_ID });
  if (!liff.isLoggedIn()) return liff.login();
  const profile = await liff.getProfile();
  document.getElementById("userId").value = profile.userId;
  document.getElementById("submitBtn").disabled = false;
}

document.getElementById("orderForm").addEventListener("submit", async (e) => {
  e.preventDefault();
  const payload = {
    lineUserId: document.getElementById("userId").value,
    items: [{ productName: document.getElementById("product").value, quantity: Number(document.getElementById("quantity").value), price: 60 }],
    phone: document.getElementById("phone").value,
    pickup: document.getElementById("pickup").value
  };
  if (!payload.items[0].productName || payload.items[0].quantity <= 0 || !/^09\\d{8}$/.test(payload.phone) || !payload.pickup) {
    return alert("請確認輸入資料是否正確");
  }
  await axios.post(`${API_BASE}/orders`, payload);
  alert("訂單已送出!");
  if (liff.isInClient()) liff.closeWindow();
});

init();

ngrok 指令

npx http-server -p 5173
ngrok http 5173
  • 拿到 https://xxxx.ngrok-free.app/index.html → 設定為 LIFF Endpoint URL。

    https://ithelp.ithome.com.tw/upload/images/20250930/20178868kd1OI1YK8B.png
    https://ithelp.ithome.com.tw/upload/images/20250930/201788684LFWwgy5uA.png

    取得後,就可以填入昨天建立 LIFF 的 Endpoint URL 選項中。
    https://ithelp.ithome.com.tw/upload/images/20250930/201788684uO5qm88le.png

小提醒!
如果忘記 ngrok 該如何使用,可以去回顧 Day 7 ~


Rich Menu 設定

  1. LINE OA 後台 → Rich Menu → 新增。
    https://ithelp.ithome.com.tw/upload/images/20250930/201788686dyKKvWe4V.png

  2. 按鈕動作:開啟網址 → 填入 https://xxxx.ngrok-free.app/index.html
    https://ithelp.ithome.com.tw/upload/images/20250930/20178868TuP3dj8suq.png

  3. 儲存並套用。


整體流程測試

  1. 顧客在 LINE Rich Menu 點「我要下單」。

  2. LIFF App 開啟 → 顯示表單。

  3. 填寫資料並送出 → API /orders 寫入 DB。

  4. 後端回覆成功 → 顧客看到「訂單已送出!」。

    抱歉各位,我無法做測試,不確定是不是因為 LINE 在維護,導致 LIFF 的連結我沒辦法更新,後續我會再將寫入 DB 測試這塊補上!

https://ithelp.ithome.com.tw/upload/images/20250930/20178868aDqLv7wOdP.png


重點回顧

  • LIFF 表單要能跑,Endpoint URL 必須是公開 HTTPS

  • ngrok 最快測試,不用額外伺服器。

  • Rich Menu 綁定 Endpoint URL,顧客就能一鍵開啟表單。

  • 到這裡,我們已完成 「從聊天 → 表單 → 真機測試」 的閉環。


部署補充:避免 ngrok 限制 & GitHub Pages 上線

問題:ngrok 免費限制

ngrok 免費帳號一次只能開 1 條 tunnel,如果前端、後端各開一條,就會報錯:

authentication failed: Your account is limited to 1 simultaneous ngrok agent sessions.

解法 A(我目前做法):前後端共用同一個 Express 服務

  1. 在後端 Express 加上:
const path = require("path");
app.use(express.static(path.join(__dirname, "liff-form")));

liff-form/index.htmlapp.js 交給 Express 提供,API 仍在 /orders

  1. 前端呼叫 API 時直接用相對路徑:
await axios.post("/orders", payload);
  1. 只需要一條 ngrok:
node index.js
ngrok http 3000
  1. LIFF Endpoint URL 設成:
https://<ngrok-subdomain>.ngrok-free.app/index.html

→ 好處:免 CORS、免兩條 ngrok、體驗更貼近正式上線。

解法 B:前端 GitHub Pages,後端 ngrok

  1. index.htmlapp.js push 到 GitHub repo。

  2. Settings → Pages 開啟 Pages。

  3. Endpoint URL 會是:

https://<user>.github.io/<repo>/index.html
  1. app.js 裡的 API_BASE 指到你的 ngrok 後端,例如:
const API_BASE = "https://abcd-1234.ngrok-free.app";
  1. 後端要允許 CORS:
app.use(cors({ origin: [/^https:\/\/.*\.github\.io$/] }));

→ 好處:前端有固定網址,後端仍用 ngrok。正式環境可再搬到 Vercel/Netlify。


以上兩種方式都能解決 ngrok 免費限制的問題,大家可依需求選擇。


上一篇
從聊天到表單:設計 LIFF 訂單頁面(UX + 驗證)
下一篇
店家需要的後台:Admin 管理介面雛形
系列文
用 LINE OA 打造中小企業訂單系統:從零開始的 30 天實作紀錄22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言